package com.baibei.ebec.sdk.interceptor;

import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;

import com.baibei.ebec.sdk.ApiConstant;
import com.baibei.ebec.sdk.BuildConfig;
import com.baibei.ebec.sdk.SDKEncryptUtils;
import com.baibei.ebec.sdk.TokenInfo;
import com.baibei.model.UserInfo;
import com.baibei.sdk.JsonBody;
import com.baibei.sdk.SdkConfig;
import com.blankj.utilcode.utils.LogUtils;
import com.google.gson.Gson;
import com.rae.swift.session.SessionManager;
import com.squareup.okhttp3.utils.SignUtils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okio.Buffer;

/**
 * 请求参数拦截器
 * Created by ChenRui on 2017/4/27 0027 15:47.
 */
public class RequestInterceptor implements Interceptor {

    private final SdkConfig mConfig;
    private String mAppVersion;
    private String mDeviceId;
    //    private final Context mContext;
    private SessionManager mSessionManager;

    public RequestInterceptor(Context context, SdkConfig config) {
//        mContext = context;
        mSessionManager = SessionManager.getDefault();
        mConfig = config;
        try {
            mAppVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_META_DATA).versionName;
        } catch (Exception e) {
            e.printStackTrace();
            mAppVersion = "1.0.0";
        }
    }

    @Override
    public Response intercept(final Chain chain) throws IOException {
        return intercept(chain, false);
    }


    public Response intercept(final Chain chain, boolean isRetry) throws IOException {
        // 添加统一头部
        String accessToken = mSessionManager.getUserToken() == null ? "" : ((TokenInfo) mSessionManager.getUserToken()).getAccessToken();

        Request.Builder builder = chain.request().newBuilder();
        if (isRetry) {
            builder.addHeader("HTTP-RETRY-TAG", "RAE");
        }

        Request request = builder
                .removeHeader(ApiConstant.APP_U_KEY_NAME)
                .removeHeader(ApiConstant.ACCESS_TOKEN_KEY)
                .addHeader(ApiConstant.ACCESS_TOKEN_KEY, accessToken == null ? "" : accessToken)
                .addHeader("Content-Type", "application/json")
                .addHeader(ApiConstant.APP_U_KEY_NAME, BuildConfig.APPKEY) // 每次请求都要带的
                .build();

        try {
            // 参数转换
            if (request.method().equalsIgnoreCase("DELETE")) {
                request = deleteMethodRequest(request); // DELETE
            } else if (request.method().equalsIgnoreCase("GET")) {
                request = getMethodRequest(request); // GET
            } else {
                request = postMethodRequest(request); // POST
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        return chain.proceed(request);
    }

    private Request deleteMethodRequest(Request request) throws Exception {

        String method = request.method();
        String body = params2JsonBody(Uri.parse(request.url().toString()), request);
        JsonBody requestBody = new JsonBody(body);
        request = request.newBuilder()
                .method(method, requestBody)
                .build();
        return request;
    }

    // 读请求参数的流
    private String bufferRequestBody(Request request) {
        try {
            if (request.body() != null && request.body().contentLength() > 0L) {
                Buffer e = new Buffer();
                request.body().writeTo(e);
                return e.readString(Charset.forName("UTF-8"));
            } else {
                return null;
            }
        } catch (IOException var3) {
            var3.printStackTrace();
            return null;
        }
    }

    /**
     * GET 请求参数转换
     */
    private Request getMethodRequest(Request request) throws Exception {
        HttpUrl url = request.url();
        HttpUrl.Builder builder = url.newBuilder();
        Set<String> parameterNames = url.queryParameterNames();

        Map<String, String> dataMap = new HashMap<>();
        for (String key : parameterNames) {
            builder.removeAllQueryParameters(key); // 移除以前的参数
            String value = url.queryParameter(key);
            dataMap.put(key, value);
        }

        JSONObject object = buildRequestBody(request, dataMap);
        Iterator<String> keys = object.keys();
        while (keys.hasNext()) {
            String key = keys.next();
            String value = object.get(key).toString();
            builder.addQueryParameter(key, value);
        }

        return request.newBuilder().url(builder.build()).build();
    }

    /**
     * 重新组合参数
     *
     * @param uri 路径
     */
    private String params2JsonBody(Uri uri, Request request) throws JSONException {

        Map<String, String> dataMap = new HashMap<>();

        if (uri.getQueryParameterNames().size() > 0) {
            // json 格式
            if (uri.getQuery() != null && uri.getQuery().startsWith("{")) {
                JSONObject jsonObject = new JSONObject(uri.getQuery());
                Iterator<String> keys = jsonObject.keys();
                while (keys.hasNext()) {
                    String key = keys.next();
                    String val = jsonObject.get(key).toString();
                    dataMap.put(key, val);
                }
            } else {
                for (String key : uri.getQueryParameterNames()) {
                    // 数组格式
                    if (key.contains("[]")) {
                        List<String> parameters = uri.getQueryParameters(key);
                        JSONArray arr = new JSONArray();
                        for (String parameter : parameters) {
                            arr.put(parameter);
                        }
                        dataMap.put(key.replace("[]", ""), arr.toString());
                    } else {
                        String val = uri.getQueryParameter(key);
                        dataMap.put(key, val);
                    }
                }
            }
        }

        return buildRequestBody(request, dataMap).toString();
    }


    private String encode(String value) {
        if (TextUtils.isEmpty(value)) return value;
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 构建请求body
     *
     * @param request 请求
     * @param dataMap 参数列表
     * @return
     * @throws JSONException
     */
    private JSONObject buildRequestBody(Request request, Map<String, String> dataMap) throws JSONException {
        final String pageFieldName = "currentPage";
        final String pageSizeFieldName = "pageSize";
        String appSecret = BuildConfig.APPSECRETE;
        String accessToken = request.header(ApiConstant.ACCESS_TOKEN_KEY);

        // 解析data
        JSONObject root = new JSONObject();
        JSONObject data = new JSONObject();
        JSONObject page = new JSONObject();

        //交易所不为空，添加
        if (!TextUtils.isEmpty(BuildConfig.EXCHANGE)) {
            root.put("exchange", encode(BuildConfig.EXCHANGE));
        }
        if (SessionManager.getDefault().getUser() != null){
            root.put("userId",((UserInfo) SessionManager.getDefault().getUser()).getUserId()+"");
        } else {
            root.put("userId","0");
        }
        root.put("requestId", encode(UUID.randomUUID().toString()));
        root.put("deviceId", encode(getDeviceId()));
        root.put("memberChannel", encode(ApiConstant.MEMBER_CHANNEL));
        root.put("timestamp", System.currentTimeMillis());
        root.put("appKey", encode(BuildConfig.APPKEY));
//        root.put("platform", encode("server"));
        root.put("platform",encode("server"));
        root.put("version", encode(mAppVersion));
        if (!TextUtils.isEmpty(accessToken)) {
            root.put("accessToken", encode(accessToken));
        }

        // 是否为重新发送的请求
        if (!TextUtils.isEmpty(request.header("HTTP-RETRY-TAG"))) {
            if (dataMap.containsKey("data") && !TextUtils.isEmpty(dataMap.get("data"))) {
                String dataJson = dataMap.get("data");
                JSONObject obj = new JSONObject(dataJson);
                Iterator<String> keys = obj.keys();
                while (keys.hasNext()) {
                    String dataKey = keys.next();
                    data.put(dataKey, obj.getString(dataKey));
                }
            }
        } else {
            Set<Map.Entry<String, String>> entries = dataMap.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                String key = entry.getKey();

                String value = entry.getValue().trim();
                String encodeValue = encode(value);

                // 密码处理，debug环境不处理

                if (
                        !BuildConfig.BUILD_TYPE.equalsIgnoreCase("debug")&&
                        TextUtils.equals("password", key)
                                && !TextUtils.isEmpty(appSecret)
                                && appSecret.length() == 32) {
                    String pk = appSecret.substring(0, 16);
                    String iv = appSecret.substring(16);

                    data.put(key, encode(SDKEncryptUtils.encrypt(value, pk, iv)));
                    continue;
                }


                // JSON Array 类型
                if (value.startsWith("[")) {
                    data.putOpt(key, new JSONArray(value));
                    continue;
                }
                // JSON Object 类型
                if (value.startsWith("{")) {
                    data.putOpt(key, new JSONObject(value));
                    continue;
                }

                if (TextUtils.equals("page", key)) {
                    page.put(pageFieldName, encodeValue);
                    continue;
                }
                if (TextUtils.equals("pageSize", key)) {
                    page.put(pageSizeFieldName, encodeValue);
                    continue;
                }
                if (TextUtils.equals("refreshAppKey", key)) {
                    root.put("refreshAppKey", encodeValue);
                    continue;
                }

                data.put(key, encodeValue);
            }
        }


        if (page.length() > 0) {
            if (!page.has("pageSize")) {
                page.put(pageSizeFieldName, ApiConstant.PAGE_SIZE); // 默认分页
            }
//             // PAGE 放在DATA里面
//            data.put(pageFieldName, page.getInt(pageFieldName));
//            data.put(pageSizeFieldName, page.getInt(pageSizeFieldName));

            // page 放在外面
            root.put("page", page);
        }

        if (data.length() > 0) {
            root.putOpt("data", data); // DATA数据
        }

        // 参数签名
        Map<String, Object> signMap = new LinkedHashMap<>();
        Iterator<String> iterator = root.keys();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (root.isNull(key) || TextUtils.isEmpty(root.get(key).toString())) continue;

            // data 移到外面签名
            if (TextUtils.equals("data", key)) {
                Iterator<String> dataKeys = data.keys();
                while (dataKeys.hasNext()) {
                    String dataKey = dataKeys.next();
                    signMap.put(dataKey, data.get(dataKey));
                }
            }
            // page 移到外面签名
            else if (TextUtils.equals("page", key)) {
                Iterator<String> pageKeys = page.keys();
                while (pageKeys.hasNext()) {
                    String pageKey = pageKeys.next();
                    signMap.put(pageKey, page.get(pageKey));
                }
            } else {
                signMap.put(key, root.get(key));
            }
        }

//        String sign = encode(SDKEncryptUtils.generateSign(true, SDKEncryptUtils.ENCODE_TYPE_BASE64, appSecret, request.url().encodedPath(), signMap));
//        String sign = URLEncoder.encode(SDKEncryptUtils.generateSign(appSecret, request.url().encodedPath(), signMap));
        String sign = compare(data);

        LogUtils.i("rae-api-sign", "签名：" + sign);
        root.put("sign", sign);



        dataMap.clear();
        signMap.clear();



        LogUtils.i("api_request", "请求入参:" + root);
        return root;
    }


    private Request postMethodRequest(Request request) throws Exception {

        String body = bufferRequestBody(request);

        Uri uri;
        if (TextUtils.isEmpty(body)) {
            uri = Uri.parse("http://www.baibei.com/api");
        } else {
            uri = Uri.parse("http://www.baibei.com/api?" + body);
        }

        String method = request.method();
        body = params2JsonBody(uri, request);
        JsonBody requestBody = new JsonBody(body);
        request = request.newBuilder()
                .method(method, requestBody)
                .build();
        return request;

    }

    /**
     * 获取设备ID
     */
    @NonNull
    private String getDeviceId() {
        // 有值直接返回
        if (!TextUtils.isEmpty(mDeviceId)) return mDeviceId;
        // 从配置文件中获取
        mDeviceId = mConfig.getDeviceId();

        // 如果为空，自动生产
        if (TextUtils.isEmpty(mDeviceId)) {
            // BB-时间戳-UUID
            mDeviceId = "BB-" + System.currentTimeMillis() + "-" + UUID.randomUUID().toString();
            mConfig.setDeviceId(mDeviceId);
        }

        return mDeviceId;
    }

    public static String compare(JSONObject data){
        if (data.length() == 0){
            return null;
        }
        Gson gson = new Gson();
        Map<String,Object> m= gson.fromJson(data.toString(),HashMap.class) ;
        Map<String,Object> n=new TreeMap<String,Object>(new Comparator<Object>() {

            @Override
            public int compare(Object o1, Object o2) {
                return o1.toString().compareTo(o2.toString());
            }
        });
        n.putAll(m);
        StringBuilder str=new StringBuilder();

        for (Map.Entry<String, Object> s : n.entrySet()) {
            str.append(s.getKey());
            str.append(s.getValue());
        }
        System.out.println("排序后"+str);
        return md5(str.toString());
    }
    public static String md5(String string) {
        byte[] hash;
        try {
            hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Huh, MD5 should be supported?", e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Huh, UTF-8 should be supported?", e);
        }

        StringBuilder hex = new StringBuilder(hash.length * 2);
        for (byte b : hash) {
            if ((b & 0xFF) < 0x10) hex.append("0");
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();
    }
}
